package com.united.ucts.modules.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.united.frame.cache.redis.RedisService;
import com.united.frame.common.constant.AuthConstant;
import com.united.frame.common.module.service.impl.BaseServiceImpl;
import com.united.ucts.modules.system.mybatis.mapper.ResourceMapper;
import com.united.ucts.modules.system.mybatis.mapper.RoleMapper;
import com.united.ucts.modules.system.mybatis.mapper.RoleResourceRelationMapper;
import com.united.ucts.modules.system.pojo.po.Resource;
import com.united.ucts.modules.system.pojo.po.Role;
import com.united.ucts.modules.system.pojo.po.RoleResourceRelation;
import com.united.ucts.modules.system.service.ResourceService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
 * 后台资源管理业务逻辑接口实现类
 *
 * @author Hudan
 * @version 1.0
 * @filename ResourceService.java
 * @copyright <a href="www.united.cn">www.united.cn</a>
 * @date 2019-11-23
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class ResourceServiceImpl extends BaseServiceImpl<ResourceMapper, Resource> implements ResourceService {

    private final RoleMapper roleMapper;
    private final RoleResourceRelationMapper roleResourceRelationMapper;
    private final RedisService redisService;

    /**
     * 添加资源
     *
     * @param resource 需要添加的资源信息
     * @return 添加结果
     */
    @Override
    public Boolean create(Resource resource) {
        // 保存新增资源信息
        boolean result = this.save(resource);

        // 新增资源后,需要重新初始化角色-资源关联映射关系
        if (result) {
            initResourceRolesMap();
        }
        return result;
    }

    @Override
    public Boolean delete(String id) {
        boolean result = this.removeById(id);

        // 删除资源后,需要重新初始化角色-资源关联映射关系
        if (result) {
            initResourceRolesMap();
        }
        return result;
    }

    /**
     * 修改资源
     *
     * @param id       需要修改的资源ID
     * @param resource 需要修改的资源信息
     * @return 修改结果
     */
    @Override
    public Boolean update(String id, Resource resource) {
        resource.setId(id);
        boolean result = this.updateById(resource);

        // 修改资源后,需要重新初始化角色-资源关联映射关系
        if (result) {
            initResourceRolesMap();
        }
        return result;
    }

    /**
     * 获取资源详情
     *
     * @param id 资源ID
     * @return 资源详情
     */
    @Override
    public Resource detail(String id) {
        return this.getById(id);
    }

    /**
     * 分页查询资源
     *
     * @param pageNum     当前页数
     * @param pageSize    每页大小
     * @param categoryId  资源分类类型
     * @param nameKeyword 资源名称关键词
     * @param urlKeyword  资源url关键词
     * @return 分页结果
     */
    @Override
    public List<Resource> pageBy(Integer pageNum, Integer pageSize, String categoryId, String nameKeyword, String urlKeyword) {
        PageHelper.startPage(pageNum, pageSize);

        LambdaQueryWrapper<Resource> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Resource::getCategoryId, categoryId)
                .like(Resource::getName, nameKeyword)
                .like(Resource::getUrl, urlKeyword);
        return this.list(queryWrapper);
    }

    /**
     * 查询全部有效资源
     *
     * @return 所有有效结果
     */
    @Override
    public List<Resource> listAll() {
        return this.list(new LambdaQueryWrapper<>());
    }

    /**
     * 初始化系统全局的角色-资源映射关系信息
     *
     * @return 角色-资源映射关系信息
     */
    @Override
    public Map<String, List<String>> initResourceRolesMap() {
        Map<String, List<String>> resourceRoleMap = new TreeMap<>();
        List<Resource> resourceList = this.listAll();

        List<Role> roleList = roleMapper.selectList(new LambdaQueryWrapper<>());
        List<RoleResourceRelation> relationList = roleResourceRelationMapper.selectList(new LambdaQueryWrapper<>());
        for (Resource resource : resourceList) {
            Set<String> roleIds = relationList.stream().filter(item -> item.getResourceId().equals(resource.getId())).map(RoleResourceRelation::getRoleId).collect(Collectors.toSet());
            List<String> roleNames = roleList.stream().filter(item -> roleIds.contains(item.getId())).map(item -> item.getId() + "_" + item.getName()).collect(Collectors.toList());
            resourceRoleMap.put("/" + applicationName + resource.getUrl(), roleNames);
        }

        redisService.del(AuthConstant.RESOURCE_ROLES_MAP_KEY);
        redisService.hSetAll(AuthConstant.RESOURCE_ROLES_MAP_KEY, resourceRoleMap);
        return resourceRoleMap;
    }
}